package com.yoso.core.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.yoso.core.bo.TreeNode;
import com.yoso.core.constant.CoreConstant;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 树结构工具
 * @author shizejin
 * @date 2023/12/11 16:01
 */
public class TreeUtil {

    /**
     * 将列表转换为树结构
     *
     * @param dataList   数据列表
     * @param comparator 排序规则
     * @return {@link List }<{@link T }>
     * @author shizejin
     * @date 2023/12/11 15:16
     */
    public static <T extends TreeNode> List<T> convertList2Tree(List<T> dataList, Comparator<T> comparator) {
        Map<String, List<T>> parentId2List = CollStreamUtil.groupByKey(dataList, TreeNode::getParentId);
        List<T> parentList = parentId2List.get(CoreConstant.TREE_ROOT_ID);
        return generateTreeRecursion(parentList, parentId2List, comparator);
    }

    /**
     * 递归生成树
     *
     * @param parentList    根列表
     * @param parentId2List 以父id分组的map
     * @param comparator    排序规则 可以为空，默认用id排序
     * @return {@link List }<{@link T }>
     * @author shizejin
     * @date 2023/12/11 15:15
     */
    public static <T extends TreeNode> List<T> generateTreeRecursion(
            List<T> parentList, Map<String, List<T>> parentId2List, Comparator<T> comparator) {
        if (CollUtil.isEmpty(parentList)) {
            return new ArrayList<>();
        }
//        默认用id排序
        comparator = Optional.ofNullable(comparator).orElse(Comparator.comparing(T::getId));
        parentList = parentList.stream().filter(node -> StrUtil.isNotBlank(node.getParentId()))
                .sorted(comparator).collect(Collectors.toList());

        for (T node : parentList) {
            List<T> children = parentId2List.get(node.getId());
            node.setChildren(children);
            generateTreeRecursion(children, parentId2List, comparator);
        }
        return parentList;
    }



    /**
     * 递归获取树的所有节点
     * @param tree 树
     * @return {@link List }<{@link T }>
     * @author shizejin
     * @date 2024/01/22 09:37
     */
    public static <T extends TreeNode> List<T> recursionGet(List<T> tree) {
        List<T> resultList = new ArrayList<>();
        if (CollUtil.isEmpty(tree)) {
            return resultList;
        }
        for (T node : tree) {
            resultList.add((T) BeanUtil.copyProperties(node, node.getClass(), "children"));
            CollUtil.addAll(resultList, recursionGet(node.getChildren()));
        }
        return resultList;
    }


    /**
     * 将列表转换为树，并且根据节点过滤
     * @param list        数据列表
     * @param nodeIdList  需要包含的节点
     * @param comparator  排序规则
     * @return {@link List }<{@link T }>
     * @author shizejin
     * @date 2024/01/22 10:45
     */
    public static <T extends TreeNode> List<T> generateAndFilterTree(List<T> list, List<String> nodeIdList, Comparator<T> comparator) {
        List<T> tree = new ArrayList<>();
        if (CollUtil.isEmpty(list) || CollUtil.isEmpty(nodeIdList)) {
            return tree;
        }
        tree = convertList2Tree(list, comparator);
        filterContainsNode(tree, nodeIdList);
        return tree;
    }


    /**
     * 根据节点过滤树
     * @param tree        树列表
     * @param nodeIdList  需要包含的节点
     * @author shizejin
     * @date 2024/01/22 10:46
     */
    public static <T extends TreeNode> void filterContainsNode(List<T> tree, List<String> nodeIdList) {
        if (CollUtil.isEmpty(tree) || CollUtil.isEmpty(nodeIdList)) {
            return;
        }
        Iterator<T> iterator = tree.iterator();
        while (iterator.hasNext()) {
            T node = iterator.next();
            filterContainsNode(node.getChildren(), nodeIdList);
            if (!nodeIdList.contains(node.getId()) && CollUtil.isEmpty(node.getChildren())) {
                iterator.remove();
            }
        }
    }

    /**
     * 裁剪当前树到指定深度
     * @param tree   树
     * @param depth  深度
     * @author shizejin
     * @date 2024/03/15 08:37
     */
    public static <T extends TreeNode> void cutTree2TargetDepth(List<T> tree, int depth) {
        cutTree2TargetDepthRecursion(tree, depth, 1);
    }

    /**
     * 裁剪当前树到指定深度
     * @param nodeList   某个分支上的节点（当前节点）
     * @param targetDepth 目标深度
     * @param currentDepth 当前节点的深度
     * @author shizejin
     * @date 2024/03/15 08:37
     */
    private static <T extends TreeNode> void cutTree2TargetDepthRecursion(
            List<T> nodeList, final int targetDepth, int currentDepth) {

        if (CollUtil.isEmpty(nodeList)) {
            return;
        }
//        第n次递归
        if (currentDepth >= targetDepth) {
            nodeList.forEach(node -> node.setChildren(new ArrayList<>()));
        } else {
            int nextDepth = currentDepth + 1;
            for (T node : nodeList) {
                cutTree2TargetDepthRecursion(node.getChildren(), targetDepth, nextDepth);
            }
        }
    }

}
